//
// Created by benxb on 2021/10/9.
//

#include "data_page.h"
#include "pair.h"
#include <type/value.h>

#include <utility>

namespace benxdb {

void DataPage::Init(page_id_t page_id, page_id_t prev_page_id, uint32_t tuple_size) {
    // Set the page ID.
    memcpy(GetData(), &page_id, sizeof(page_id));
    // Set the previous and next page IDs.
    SetPrevPageId(prev_page_id);
    SetNextPageId(INVALID_PAGE_ID);
    SetPairCount(0);
    SetPairSize(tuple_size);
}

bool DataPage::AppendPair(const Pair& pair) {
    BUSTUB_ASSERT(pair.GetLength() > 0, "Cannot have empty pair.");
    BUSTUB_ASSERT(pair.GetLength() == GetPairSize(), "Cannot have empty pair.");
    // If there is not enough space, then return false.
    if (GetFreeSpaceRemaining() < pair.GetLength() + sizeof(uint32_t)) {
        return false;
    }

    // available free space..
    memcpy(GetFreeSpacePointer(), pair.GetData(), pair.GetLength());

    SetPairCount(GetPairCount() + 1);
    return true;
}

bool DataPage::UpdatePair(uint32_t offset, const Pair& pair) {
    if (offset >= GetPairCount()) {
        return false;
    }
    pair.SerializeTo(GetData() + SIZE_DATA_PAGE_HEADER + offset * GetPairSize());
    return true;
}

void DataPage::Delete(const uint32_t &rid) {
    uint32_t total = GetPairCount();
    std::shared_ptr<Pair> pair(new Pair);
    for (int i = 0; i < total; i++) {
        if (!GetPair(i, pair)) {
            return;
        }
        if (pair->GetRid() != rid) {
            continue;
        }
        if (i < total-1) {
            // move last tuple to here
            GetLastPair(pair);
            UpdatePair(i, *pair);
        }
        SetPairCount(GetPairCount() - 1);
    }
}

bool DataPage::GetPair(uint32_t offset, const std::shared_ptr<Pair>& pair) {
    if (offset > GetPairSize()) {
        return false;
    }
    pair->DeserializeFrom(GetData() + SIZE_DATA_PAGE_HEADER + offset * GetPairSize());
    return true;
}

bool DataPage::GetLastPair(const std::shared_ptr<Pair>& pair) {
    return GetPair(GetPairCount() - 1, pair);
}

}